﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Core.ScreenStore.ViewModel;
using ThemeLoader;
using TypeMock.ArrangeActAssert;
using Core.Model;
using System.Windows;
using NUnit.Framework;
using Core.Infrastructure.ErrorReportService;
using CThru.Silverlight;

namespace Core.ScreenStore.Test
{
    public class ThemeSelectViewModelTests
    {
        private IErrorReportService errorReportService;

        [SetUp, SilverlightSetUp]
        public void Setup()
        {
            errorReportService = Isolate.Fake.Instance<IErrorReportService>();
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeIsLoaded_IsNotBusy()
        {
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, null, themeManager, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = true });

            Assert.IsFalse(viewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeIsLoadedAndIsNotBusy_ThemeManagerCallsApplyTheme()
        {
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, null, themeManager, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = true });

            Isolate.Verify.WasCalledWithAnyArguments(() => themeManager.ApplyTheme(null));
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeIsNotLoadedAndIsNotBusy_ThemeLoaderCallsDownloadTheme()
        {
            IThemeLoader loader = Isolate.Fake.Instance<IThemeLoader>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, loader, null, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel()
            {
                ZippedThemeFilePath = "ZippedResources/Style1.zip",
                ResourcePath = "Style1.xaml",
                IsLoaded = false,
            });

            Isolate.Verify.WasCalledWithArguments(() => loader.DownloadTheme("ZippedResources/Style1.zip", "Style1.xaml", e => { }))
                           .Matching(args =>
                               {
                                   var firstArgMatch = args[0].ToString() == "ZippedResources/Style1.zip";
                                   var secondArgMacth = args[1].ToString() == "Style1.xaml";
                                   return firstArgMatch && secondArgMacth;
                               });
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeIsNotLoadedAndIsNotBusy_IsBusy()
        {
            IThemeLoader loader = Isolate.Fake.Instance<IThemeLoader>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, loader, null, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = false });

            Assert.IsTrue(viewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ThemeSelect_IsBusy_ThrowInvalidOperation()
        {
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, null, null, GetNotLoadedThemeModels(), errorReportService);
            viewModel.IsBusy = true;

            viewModel.SelectTheme(new ThemeModel());
        }

        [Test, SilverlightUnitTest]
        public void CanThemeSelect_IsBusy_ReturnFalse()
        {
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, null, null, GetNotLoadedThemeModels(), errorReportService);
            viewModel.IsBusy = true;

            Assert.IsFalse(viewModel.CanSelectTheme(new ThemeModel()));
        }

        [Test, SilverlightUnitTest]
        public void CanThemeSelect_IsNotBusy_ReturnTrue()
        {
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, null, null, GetNotLoadedThemeModels(), errorReportService);
            viewModel.IsBusy = false;

            Assert.IsTrue(viewModel.CanSelectTheme(new ThemeModel()));
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadSuccessfully_ThemeManagerCallsApplyTheme()
        {
            IThemeLoader successThemeloader = GetSuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, successThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = false });

            Isolate.Verify.WasCalledWithAnyArguments(() => themeManager.ApplyTheme(null));
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadSuccessful_IsBusyReturnsFalse()
        {
            IThemeLoader successThemeloader = GetSuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, successThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = false });

            Assert.IsFalse(viewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadSuccessful_ThemeIsLoaded()
        {
            IThemeLoader successThemeloader = GetSuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, successThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);
            ThemeModel themeModel = new ThemeModel() { IsLoaded = false };

            viewModel.SelectTheme(themeModel);

            Assert.IsTrue(themeModel.IsLoaded);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadSuccessful_ThemeStylesNotNull()
        {
            IThemeLoader successThemeloader = GetSuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, successThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);
            ThemeModel themeModel = new ThemeModel() { IsLoaded = false };

            viewModel.SelectTheme(themeModel);

            Assert.NotNull(themeModel.Styles);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadUnsuccessfully_IsBusyReturnsFalse()
        {
            IThemeLoader unsuccessfulThemeloader = GetUnsuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, unsuccessfulThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = false });

            Assert.IsFalse(viewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadUnsuccessfully_ThemeNotIsLoaded()
        {
            IThemeLoader unsuccessfulThemeloader = GetUnsuccessfulThemeLoader();
            IThemeManager themeManager = Isolate.Fake.Instance<IThemeManager>();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, unsuccessfulThemeloader, themeManager, GetNotLoadedThemeModels(), errorReportService);
            ThemeModel themeModel = new ThemeModel() { IsLoaded = false };

            viewModel.SelectTheme(themeModel);

            Assert.IsFalse(themeModel.IsLoaded);
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadUnsuccessfullyMoreThan1ThemeOnList_ThemeIsRemovedFromList()
        {
            IThemeLoader unsuccessfulThemeloader = GetUnsuccessfulThemeLoader();
            IEnumerable<ThemeModel> themeModels = GetNotLoadedThemeModels();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, unsuccessfulThemeloader, null, themeModels, errorReportService);

            viewModel.SelectTheme(themeModels.FirstOrDefault());

            Assert.AreEqual(1, viewModel.Themes.Count());
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadUnsuccessfullyOneThemeOnList_ClearThemeList()
        {
            IThemeLoader unsuccessfulThemeloader = GetUnsuccessfulThemeLoader();
            IEnumerable<ThemeModel> themeModels = GetNotLoadedThemeModels().Take(1);
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, unsuccessfulThemeloader, null, themeModels, errorReportService);

            viewModel.SelectTheme(themeModels.FirstOrDefault());

            Assert.AreEqual(0, viewModel.Themes.Count());
        }

        [Test, SilverlightUnitTest]
        public void ThemeSelect_ThemeDownloadUnsuccessfully_ErrorReporterCallsReport()
        {
            IThemeLoader unsuccessfulThemeloader = GetUnsuccessfulThemeLoader();
            ThemeSelectViewModel viewModel = new ThemeSelectViewModel(null, null, null, null, unsuccessfulThemeloader, null, GetNotLoadedThemeModels(), errorReportService);

            viewModel.SelectTheme(new ThemeModel() { IsLoaded = false });

            Isolate.Verify.WasCalledWithAnyArguments(() => errorReportService.Report("message"));
        }

        private static IThemeLoader GetSuccessfulThemeLoader()
        {
            IThemeLoader successThemeloader = Isolate.Fake.Instance<IThemeLoader>();
            Isolate.WhenCalled(() => successThemeloader.DownloadTheme(null, null, null)).DoInstead(context =>
            {
                var action = context.Parameters[2] as Action<ThemeDownloadedEventArgs>;
                var theme = Isolate.Fake.Instance<ResourceDictionary>();
                var args = new ThemeDownloadedEventArgs(null, false, null, theme);
                action(args);
            });

            return successThemeloader;
        }

        private static IThemeLoader GetUnsuccessfulThemeLoader()
        {
            IThemeLoader unssuccessfulThemeloader = Isolate.Fake.Instance<IThemeLoader>();
            Isolate.WhenCalled(() => unssuccessfulThemeloader.DownloadTheme(null, null, null)).DoInstead(context =>
            {
                var action = context.Parameters[2] as Action<ThemeDownloadedEventArgs>;
                var args = new ThemeDownloadedEventArgs(new Exception(), false, null, null);
                action(args);
            });

            return unssuccessfulThemeloader;
        }

        private static IEnumerable<ThemeModel> GetNotLoadedThemeModels()
        {
            IEnumerable<ThemeModel> themeModels = new List<ThemeModel>()
            {
                new ThemeModel() { IsLoaded = false },
                new ThemeModel() { IsLoaded = false },
            };

            return themeModels;
        }
    }
}
